package map;

import image.WebImage;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import figures.Figure;
import figures.FigureIterator;
import figures.basic.ImageFigure;
import figures.basic.PoliLine;
import geometry.Point;
import geometry.Rectangle;

public class DBMap implements Map {

	MemMap m = new MemMap();
	private int map;
	private Connection conn=null;
	private HashMap<Integer, Class> object_type_map = new HashMap<Integer, Class>();
	private String dsn=null;

	public FigureIterator getFigures(Rectangle a) {
		return m.getFigures(a);
	}

	public DBMap(String host, String server, String user, String pass, String map_name, String version){
		dsn = "jdbc:mysql://"+host+"/"+server+"?user="+user+"&password="+pass;
		connect();
		try {
			getMapId(map_name, version);
			loadTypes();
			loadFigures();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			conn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	/**
	 * 
	 */
	private void connect() {
		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			conn = DriverManager.getConnection(dsn);
        } catch (SQLException ex) {
            // handle any errors
            System.out.println("SQLException: " + ex.getMessage());
            System.out.println("SQLState: " + ex.getSQLState());
            System.out.println("VendorError: " + ex.getErrorCode());
        } catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void getMapId(String map_name, String version) throws IOException {
		try {
			Statement s = conn.createStatement();
			s.execute("SELECT map FROM map WHERE map_name='"+map_name+"' and version='"+version+"'");
			ResultSet rs = s.getResultSet();
			if(rs.next()){
				map = rs.getInt("map");
				if(rs.next()){
					rs.close();
					throw new IOException("2 maps share the name"+map_name);
				}
			}else{
				Statement u = conn.createStatement();
				u.executeUpdate(
			            "INSERT INTO map (map_name) "
			            + "values ('"+map_name+"')",
			            Statement.RETURN_GENERATED_KEYS);
				map = -1;
				ResultSet rs2 = u.getGeneratedKeys();
			    if (rs2.next()) {
			        map = rs2.getInt(1);
			    } else {
			    	throw new IOException();
			    }
			    rs2.close();
				u.close();
			}
			rs.close();
			s.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	private void loadTypes() {
		try {
			Statement s = conn.createStatement();
			s.executeQuery("SELECT object_type, classname FROM object_type");
			ResultSet rs = s.getResultSet();
			while(rs.next()){
				int object_type = rs.getInt("object_type");
				String classname= rs.getString("classname");
				object_type_map.put(object_type, Class.forName(classname));
			}
			rs.close();
			s.close();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void loadFigures() {
		HashMap<Integer, List<Point>> v =preLoadVertex();
		try {
			Statement s = conn.createStatement();
			s.executeQuery("SELECT object, object_type, object_name FROM object WHERE map="+map);
			ResultSet rs = s.getResultSet();
			while(rs.next()){
				int object = rs.getInt("object");
				int object_type = rs.getInt("object_type");
				String name = rs.getString("object_name");
				m.appendFigure(createFigure(object, object_type_map.get(object_type),name, v));
			}
			rs.close();
			s.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	private HashMap<Integer, List<Point>> preLoadVertex() {
		HashMap<Integer, List<Point>> r = new HashMap<Integer, List<Point>>();
		try {
			Statement s = conn.createStatement();
			s.executeQuery("SELECT object, x, y FROM object_vertex WHERE map="+map+" ORDER BY object, vertex");
			ResultSet rs = s.getResultSet();
			while(rs.next()){
				int object = rs.getInt("object");
				int x = rs.getInt("x");
				int y = rs.getInt("y");
				if(!r.containsKey(object))
					r.put(object, new LinkedList<Point>());
				r.get(object).add(new Point(x,y));
			}
			rs.close();
			s.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return r;
	}

	private Figure createFigure(int object, Class object_class, String name, HashMap<Integer, List<Point>> v) {
		Figure f = null;
		try {
			f=(Figure) object_class.newInstance();
			f.setName(name);
			if(f instanceof PoliLine){
				PoliLine p = (PoliLine)f;
				int x[] = new int[v.get(object).size()];
				int y[] = new int[v.get(object).size()];
				int i=0;
				for(Point point:v.get(object)){
					x[i] = point.x;
					y[i] = point.y;
					i++;
				}
				p.setxy(x, y);
			}
			if(f instanceof ImageFigure){
				Point point =v.get(object).get(0);
				((ImageFigure)f).setPos(point.x, point.y);
				if(f instanceof WebImage){
					//TODO
				}
			}
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return f;
	}

	
	public static void main(String[] arg){
		DBMap m = new DBMap("192.168.15.2", "celumap", "celumap", "florida", "london", "0.1");
		FigureIterator i = m.getFigures(null);
		while(i.hasNext())
			System.out.println(new String(i.next().getName()));
	}
}
